package driver

import (
	"gitee.com/sweetsunnyflower/carpooling-server-go/app/models/driver"
	"gitee.com/sweetsunnyflower/carpooling-server-go/app/models/user"

	v1 "gitee.com/sweetsunnyflower/carpooling-server-go/app/http/controllers/api/v1"
	"gitee.com/sweetsunnyflower/carpooling-server-go/app/models/region"
	"gitee.com/sweetsunnyflower/carpooling-server-go/app/models/track"
	"gitee.com/sweetsunnyflower/carpooling-server-go/app/models/trip"

	"gitee.com/sweetsunnyflower/carpooling-server-go/app/models/vehicle"

	"gitee.com/sweetsunnyflower/carpooling-server-go/app/policies"
	"gitee.com/sweetsunnyflower/carpooling-server-go/app/requests"
	"gitee.com/sweetsunnyflower/carpooling-server-go/app/services"
	"github.com/gofiber/fiber/v2"
	"github.com/golang-module/carbon/v2"
	"github.com/spf13/cast"
)

type TripsController struct {
	v1.BaseController
}

func (controller *TripsController) Index(c *fiber.Ctx) error {

	userId := controller.Auth(c)

	query := c.Queries()

	query["user_id"] = cast.ToString(userId)

	trips := trip.GetTripsByIdWithAll(query, 0)

	for index, trip := range trips {
		trips[index].Followed = len(trip.BeFollow) != 0
		trips[index].Booked = len(trip.TripRider) != 0
		trips[index].Owner = trip.UserId == userId
	}

	return controller.Json(c, trips)
}

func (controller *TripsController) Show(c *fiber.Ctx) error {

	userId := controller.Auth(c)

	tripModel := trip.GetTripByIdWithAll(cast.ToUint64(c.Params("id")), 0)

	tripModel.Followed = len(tripModel.BeFollow) != 0
	tripModel.Booked = len(tripModel.TripRider) != 0
	tripModel.Owner = tripModel.UserId == userId

	if ok := policies.CanViewTrip(userId, tripModel); !ok {
		return controller.Forbidden(c)
	}

	if tripModel.ID == 0 {
		return controller.NotFound(c)
	}

	return controller.Json(c, tripModel)
}

func (controller *TripsController) Store(c *fiber.Ctx) error {

	userId := controller.Auth(c)

	/// todo 检查是否有正在时间段内进行中的行程，如果有，不允许发布新的行程，除非自己手动先结束
	latestTrip := trip.GetUserLatestTrip(userId)
	if latestTrip.ID > 0 {
		if latestTrip.Status != trip.CANCEL && latestTrip.Status != trip.FINISH {
			return controller.Faield(c, "您还有正在进行中的行程")
		}
	}

	request := new(requests.TripRequest)

	if errors := requests.ValidateTrip(c, request); len(errors) > 0 {
		return controller.ValidationError(c, errors)
	}

	/// 需要校验 end_location 和 start_location 的正确性
	if request.StartLocation == request.EndLocation {
		return controller.Faield(c, "起点和终点不能一样")
	}

	startLocation := region.Get(request.StartLocation)
	if startLocation.ID <= 0 {
		return controller.Faield(c, "起点不存在")
	}

	endLocation := region.Get(request.EndLocation)

	if endLocation.ID <= 0 {
		return controller.Faield(c, "终点不存在")
	}

	if !track.IsExistTrack(request.StartLocation, request.EndLocation) {
		return controller.Faield(c, "线路不存在")
	}

	/// 车辆ID校验真实性
	vehicle := vehicle.Get(request.VehicleId)

	if vehicle.ID <= 0 {
		return controller.Faield(c, "车辆ID错误")
	}

	if vehicle.UserId != userId {
		return controller.Faield(c, "车辆ID错误")
	}

	/// 剩余座位数不能大于总座位数
	if request.AvailableSeats > vehicle.Seats {
		return controller.Faield(c, "车辆剩余座位大于车辆座位")
	}

	/// 如果截止时间大于发车时间，自动更正截止时间为发车时间，需要有一个脚本根据截止时间将行程状态变更为结束
	/// 还是提醒一下吧，用户手动修改
	if carbon.Parse(request.DepartureTime).DiffInSeconds(carbon.Parse(request.Deadline)) > 0 {
		return controller.Faield(c, "截止时间大于出发时间")
	}

	driver := c.Locals("driver").(driver.Driver)

	tripModel := trip.Trip{
		UserId:         userId,
		DriverId:       driver.ID,
		VehicleId:      request.VehicleId,
		StartLocation:  request.StartLocation,
		EndLocation:    request.EndLocation,
		DepartureTime:  controller.ToTime(request.DepartureTime),
		Deadline:       controller.ToTime(request.Deadline),
		TotalSeats:     vehicle.Seats,
		AvailableSeats: request.AvailableSeats,
		Price:          request.Price,
		Itinerary:      request.Itinerary,
		Status:         trip.ING,
	}

	tripModel.Create()

	driver.TripsCount = driver.TripsCount + 1

	driver.Save()

	if tripModel.ID > 0 {
		return controller.Success(c)
	} else {
		return controller.Faield(c, "创建失败")
	}
}

func (controller *TripsController) Update(c *fiber.Ctx) error {

	tripModel := trip.Get(cast.ToUint64(c.Query("id")))
	if tripModel.ID == 0 {
		return controller.NotFound(c)
	}

	userId := controller.Auth(c)
	if ok := policies.CanModifyTrip(userId, tripModel); !ok {
		return controller.Forbidden(c)
	}

	request := new(requests.TripRequest)

	if errors := requests.ValidateTrip(c, request); len(errors) > 0 {
		return controller.ValidationError(c, errors)
	}

	// tripModel.FieldName = request.FieldName
	rowsAffected := tripModel.Save()
	if rowsAffected > 0 {
		return controller.Success(c)
	} else {
		return controller.Faield(c, "更新失败")
	}
}

func (controller *TripsController) Delete(c *fiber.Ctx) error {

	tripModel := trip.Get(cast.ToUint64(c.Params("id")))
	if tripModel.ID == 0 {
		return controller.NotFound(c)
	}

	if len(tripModel.TripRider) != 0 {
		miniprogramService := services.NewMiniProgram()
		// 将订单状态更新为已取消
		for _, trip_rider := range tripModel.TripRider {
			// 通知乘客行程取消
			// 模板消息
			go func() {
				user := user.Get(trip_rider.UserId)
				miniprogramService.SubscribeMessage(trip_rider.ID, user.OpenId)
			}()

			// 站内消息
			go func() {

			}()
			trip_rider.TripStatus = trip.CANCEL
			trip_rider.Save()
		}
	}

	userId := controller.Auth(c)

	if ok := policies.CanModifyTrip(userId, tripModel); !ok {
		return controller.Forbidden(c)
	}

	rowsAffected := tripModel.Delete()

	driver := c.Locals("driver").(driver.Driver)
	driver.TripsCount = driver.TripsCount - 1
	driver.Save()

	if rowsAffected > 0 {
		return controller.Success(c)
	}

	return controller.Faield(c, "删除失败")
}
